package com.gmail.skwong.speedplayer;

import java.util.Random;

import com.gmail.skwong.speedplayer.R;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.content.SharedPreferences;

/**
 * Main Activity for application. Sets up the click listeners for buttons.
 * Handles the music player. Also has the location listener.
 * 
 * @author Stephen
 * 
 */
public class SpeedPlayer extends Activity implements OnCompletionListener,
		SeekBar.OnSeekBarChangeListener {

	private ImageButton btnPlay;
	private ImageButton btnForward;
	private ImageButton btnNext;
	private ImageButton btnBackward;
	private ImageButton btnPrevious;
	private ImageButton btnOptions;
	private SeekBar songProgressBar;
	private TextView songTitleLabel;
	private TextView speedDisplayLabel;
	private ImageView modeDisplayLabel;
	private ImageView albumArt;
	private MediaPlayer mediaplayer;
	private int seekForwardTime = 5000; // 5000 milliseconds
	private int seekBackwardTime = 5000; // 5000 milliseconds
	private Handler mHandler = new Handler();
	private SongsManager songManager;
	private ProgressBarUtilities utils;
	private boolean carMode = true;
	LocationManager locationManager;
	LocationProvider provider;
	private SensorManager sensorManager;
	private ShakeEventListener mSensorListener;
	private MagneticFieldListener mMagneticFieldListener;
	private float lastSpeed = 0;
	private boolean testMode = false;
	private boolean enableShake = true;
	private boolean enableMagnetometer = true;
	private int testSpeed = 0;

	public void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);
		setContentView(R.layout.player);

		// Associate variables with widgets
		btnPlay = (ImageButton) findViewById(R.id.btnPlay);
		btnForward = (ImageButton) findViewById(R.id.btnForward);
		btnNext = (ImageButton) findViewById(R.id.btnNext);
		btnBackward = (ImageButton) findViewById(R.id.btnBackward);
		btnPrevious = (ImageButton) findViewById(R.id.btnPrevious);
		btnOptions = (ImageButton) findViewById(R.id.btnOptions);
		songProgressBar = (SeekBar) findViewById(R.id.songProgressBar);
		songTitleLabel = (TextView) findViewById(R.id.songTitle);
		speedDisplayLabel = (TextView) findViewById(R.id.speedDisplay);
		modeDisplayLabel = (ImageView) findViewById(R.id.modeDisplay);
		albumArt = (ImageView) findViewById(R.id.albumArt);

		// setup GPS
		locationManager = (LocationManager) this
				.getSystemService(Context.LOCATION_SERVICE);
		final boolean gpsEnabled = locationManager
				.isProviderEnabled(LocationManager.GPS_PROVIDER);
		if (!gpsEnabled) {
			Toast.makeText(this, "GPS NOT ENABLED", Toast.LENGTH_SHORT).show();
			// AlertDialog.Builder alertDialogBuilder = new
			// AlertDialog.Builder(SpeedPlayer.this);

		} else {
			Location lastKnownLocation = locationManager
					.getLastKnownLocation(LocationManager.GPS_PROVIDER);
			if (lastKnownLocation != null) {
				updateSpeed(lastKnownLocation.getSpeed());
			}
		}

		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
				1000, 0, listener);

		sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

		mSensorListener = new ShakeEventListener();
		mSensorListener
				.setOnShakeListener(new ShakeEventListener.OnShakeListener() {

					@Override
					public void onShake() {
						if (mediaplayer.isPlaying() && enableShake) {
							playSongBasedOnSpeed();
						}
					}
				});

		mMagneticFieldListener = new MagneticFieldListener(this);
		mMagneticFieldListener
				.setOnMagneticSpikeListener(new MagneticFieldListener.OnMagneticSpikeListener() {

					@Override
					public void onSpike() {
						Log.w("SpeedPlayer", "Magnetic Field : "
								+ enableMagnetometer);
						if (mediaplayer.isPlaying() && enableMagnetometer) {
							playSongBasedOnSpeed();
						}
					}
				});

		btnOptions.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				// toggleMode();
				Intent i = new Intent(SpeedPlayer.this, SettingsActivity.class);
				startActivityForResult(i, 1);
			}
		});

		checkUserSettings();

		// Create media player
		mediaplayer = new MediaPlayer();
		utils = new ProgressBarUtilities();
		songManager = new SongsManager();
		new Thread(new Runnable() {
			@Override
			public void run() {
				songManager.calculateTempos();
				playSongBasedOnSpeed();
			}
		}).start();

		mediaplayer.setOnCompletionListener(this);
		songProgressBar.setOnSeekBarChangeListener(this);

		btnPlay.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {

				// If music is already playing
				if (mediaplayer.isPlaying()) {
					if (mediaplayer != null) {
						mediaplayer.pause(); // pause music
						btnPlay.setImageResource(R.drawable.btn_play);
					}
				} else {
					// resume song
					if (mediaplayer != null) {
						mediaplayer.start();
						btnPlay.setImageResource(R.drawable.btn_pause);
					}
				}
			}
		});

		btnForward.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				int currentPos = mediaplayer.getCurrentPosition();
				if (currentPos + seekForwardTime < mediaplayer.getDuration()) {
					mediaplayer.seekTo(mediaplayer.getCurrentPosition()
							+ seekForwardTime);
				} else {
					mediaplayer.seekTo(mediaplayer.getDuration());
				}
			}
		});

		btnBackward.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				int currentPos = mediaplayer.getCurrentPosition();
				if (currentPos - seekBackwardTime > 0) {
					mediaplayer.seekTo(mediaplayer.getCurrentPosition()
							- seekBackwardTime);
				} else {
					mediaplayer.seekTo(0);
				}
			}
		});

		btnNext.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				playSongBasedOnSpeed();
				// mediaplayer.seekTo(mediaplayer.getDuration());
			}
		});

		btnPrevious.setOnClickListener(new View.OnClickListener() {

			@Override
			public void onClick(View v) {
				mediaplayer.seekTo(0);
			}
		});
	}

	public void toggleMode() {
		if (carMode) {
			modeDisplayLabel.setImageResource(R.drawable.run);
		} else {
			modeDisplayLabel.setImageResource(R.drawable.car);
		}
		carMode = !carMode;
	}

	public void playSong(String songPath, String songTitle) {
		try {
			mediaplayer.reset();
			mediaplayer.setDataSource(songPath);
			mediaplayer.prepare();
			mediaplayer.start();

			songTitleLabel.setText(songTitle);

			btnPlay.setImageResource(R.drawable.btn_pause);

			songProgressBar.setProgress(0);
			songProgressBar.setMax(100);
			updateProgressBar();
		} catch (Exception e) {

		}
	}

	public void updateProgressBar() {
		mHandler.postDelayed(mUpdateTimeTask, 100);
	}

	private Runnable mUpdateTimeTask = new Runnable() {
		public void run() {
			long totalDuration = mediaplayer.getDuration();
			long currentDuration = mediaplayer.getCurrentPosition();

			int progress = (int) (utils.getProgressPercentage(currentDuration,
					totalDuration));
			songProgressBar.setProgress(progress);

			mHandler.postDelayed(this, 100);
		}
	};

	@Override
	protected void onPause() {
		super.onPause();
		sensorManager.unregisterListener(mMagneticFieldListener);
		sensorManager.unregisterListener(mSensorListener);
		mHandler.removeCallbacks(mUpdateTimeTask);
	}

	@Override
	protected void onResume() {
		super.onResume();
		checkUserSettings();
		updateProgressBar();

		sensorManager.registerListener(mMagneticFieldListener,
				sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
				SensorManager.SENSOR_DELAY_UI);
		sensorManager.registerListener(mSensorListener,
				sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_UI);

	}

	@Override
	protected void onRestart() {
		super.onRestart();
		locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
				1000, 0, listener);
	}

	@Override
	protected void onStop() {
		locationManager.removeUpdates(listener);
		super.onStop();
	}

	@Override
	public void onDestroy() {
		mediaplayer.release();
		super.onDestroy();
	}

	@Override
	public void onCompletion(MediaPlayer mp) {
		playSongBasedOnSpeed();
	}

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress,
			boolean fromUser) {
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
		mHandler.removeCallbacks(mUpdateTimeTask);
	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
		mHandler.removeCallbacks(mUpdateTimeTask);
		int percentage = seekBar.getProgress();
		int currentPosition = percentage * mediaplayer.getDuration() / 100;
		mediaplayer.seekTo(currentPosition);
		updateProgressBar();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		switch (requestCode) {
		case 1:
			checkUserSettings();
			break;
		}
	}

	private void checkUserSettings() {
		SharedPreferences sharedPrefs = PreferenceManager
				.getDefaultSharedPreferences(this);
		int mode = Integer.parseInt(sharedPrefs.getString("mode", "1"));
		switch (mode) {
		case 1:
			carMode = true;
			modeDisplayLabel.setImageResource(R.drawable.car);
			break;
		case 2:
			carMode = false;
			modeDisplayLabel.setImageResource(R.drawable.run);
			break;
		}

		enableShake = sharedPrefs.getBoolean("enableShake", enableShake);

		enableMagnetometer = sharedPrefs.getBoolean("enableMagnetometer",
				enableMagnetometer);

		testMode = sharedPrefs.getBoolean("testMode", testMode);
		if (testMode) {
			testSpeed = Integer.parseInt(sharedPrefs.getString("testSpeed",
					Integer.toString(testSpeed)));
		}

	}

	private void enableLocationSettings() {
		Intent settingsIntent = new Intent(
				Settings.ACTION_LOCATION_SOURCE_SETTINGS);
		startActivity(settingsIntent);
	}

	private void playSongBasedOnSpeed() {

		if (testMode) {
			updateSpeed(testSpeed);
		}

		int min = songManager.getMinTempo();
		int max = songManager.getMaxTempo();
		float upSpeed;
		Random rand = new Random(System.currentTimeMillis());
		if (carMode) {
			upSpeed = getResources().getInteger(R.integer.car_max_speed);
		} else {
			upSpeed = getResources().getInteger(R.integer.run_max_speed);
		}
		float tempo;
		if (lastSpeed >= upSpeed) {
			tempo = max;
			int randomNumber = rand.nextInt(getResources().getInteger(
					R.integer.randomPercent));
			float percent = (max - min) * randomNumber / 100;
			tempo -= percent;
		} else if (lastSpeed <= 0.f) {
			tempo = min;
			int randomNumber = rand.nextInt(getResources().getInteger(
					R.integer.randomPercent));
			float percent = (max - min) * randomNumber / 100;
			tempo += percent;

		} else {
			float percent = lastSpeed / upSpeed;
			percent += ((rand.nextInt(getResources().getInteger(
					R.integer.randomPercent)) - rand.nextInt(getResources()
					.getInteger(R.integer.randomPercent))) / 100);
			tempo = min + ((max - min) * percent);
		}
		Log.w("SpeedPlayer", "Tempo Selected: " + tempo);
		String title = songManager.getSongForTempo((int) tempo);
		Log.w("speedplayer", "title: " + title);
		String path = songManager.getSongPath(title);
		playSong(path, title);
		songManager.setArt(path, albumArt);
	}

	private void updateSpeed(float speed) {
		lastSpeed = speed;
		if (testMode) {
			lastSpeed = testSpeed;
		}
		speedDisplayLabel.setText("" + (int) lastSpeed + " mph");
	}

	private final LocationListener listener = new LocationListener() {

		@Override
		public void onLocationChanged(Location location) {
			float speed = location.getSpeed();
			speed *= 2.23694; // convert m/s to mi/h
			updateSpeed(speed);
		}

		@Override
		public void onProviderDisabled(String provider) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onProviderEnabled(String provider) {
			// TODO Auto-generated method stub

		}

		@Override
		public void onStatusChanged(String provider, int status, Bundle extras) {
			// TODO Auto-generated method stub

		}

	};

}
